/*
 * Copyright (c) 2009 Kathryn Huxtable and Kenneth Orr.
 *
 * This file is part of the SeaGlass Pluggable Look and Feel.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * $Id: org.eclipse.jdt.ui.prefs 172 2009-10-06 18:31:12Z kathryn@kathrynhuxtable.org $
 */
package com.seaglasslookandfeel.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Enumeration;

import javax.swing.DefaultCellEditor;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.LookAndFeel;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.plaf.synth.ColorType;
import javax.swing.plaf.synth.Region;
import javax.swing.plaf.synth.SynthConstants;
import javax.swing.plaf.synth.SynthContext;
import javax.swing.plaf.synth.SynthLabelUI;
import javax.swing.plaf.synth.SynthStyle;
import javax.swing.tree.DefaultTreeCellEditor;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import sun.swing.plaf.synth.SynthIcon;

import com.seaglasslookandfeel.SeaGlassContext;
import com.seaglasslookandfeel.SeaGlassLookAndFeel;
import com.seaglasslookandfeel.SeaGlassStyle;
import com.seaglasslookandfeel.component.SeaGlassIcon;

/**
 * @author Kathryn Huxtable
 *
 */
public class SeaGlassTreeUI extends BasicTreeUI implements PropertyChangeListener, SeaglassUI {
    private SynthStyle   style;
    private SynthStyle   cellStyle;

    private SeaGlassContext paintContext;

    private boolean      drawHorizontalLines;
    private boolean      drawVerticalLines;

    private Object       linesStyle;

    private int          padding;

    private boolean      useTreeColors;

    private Icon         expandedIconWrapper = new ExpandedIconWrapper();

    /**
     * Creates a new UI object for the given component.
     *
     * @param x
     *            component to create UI object for
     * @return the UI object
     */
    public static ComponentUI createUI(JComponent x) {
        return new SeaGlassTreeUI();
    }

    /**
     * @inheritDoc
     */
    @Override
    public Icon getExpandedIcon() {
        return expandedIconWrapper;
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void installDefaults() {
        updateStyle(tree);
    }

    private void updateStyle(JTree tree) {
        SeaGlassContext context = getContext(tree, ENABLED);
        SynthStyle oldStyle = style;

        style = SeaGlassLookAndFeel.updateStyle(context, this);
        if (style != oldStyle) {
            Object value;

            setExpandedIcon(style.getIcon(context, "Tree.expandedIcon"));
            setCollapsedIcon(style.getIcon(context, "Tree.collapsedIcon"));

            setLeftChildIndent(style.getInt(context, "Tree.leftChildIndent", 0));
            setRightChildIndent(style.getInt(context, "Tree.rightChildIndent", 0));

            drawHorizontalLines = style.getBoolean(context, "Tree.drawHorizontalLines", true);
            drawVerticalLines = style.getBoolean(context, "Tree.drawVerticalLines", true);
            linesStyle = style.get(context, "Tree.linesStyle");

            value = style.get(context, "Tree.rowHeight");
            if (value != null) {
                LookAndFeel.installProperty(tree, "rowHeight", value);
            }

            value = style.get(context, "Tree.scrollsOnExpand");
            LookAndFeel.installProperty(tree, "scrollsOnExpand", value != null ? value : Boolean.TRUE);

            padding = style.getInt(context, "Tree.padding", 0);

            largeModel = (tree.isLargeModel() && tree.getRowHeight() > 0);

            useTreeColors = style.getBoolean(context, "Tree.rendererUseTreeColors", true);

            Boolean showsRootHandles = style.getBoolean(context, "Tree.showsRootHandles", Boolean.TRUE);
            LookAndFeel.installProperty(tree, JTree.SHOWS_ROOT_HANDLES_PROPERTY, showsRootHandles);

            if (oldStyle != null) {
                uninstallKeyboardActions();
                installKeyboardActions();
            }
        }
        context.dispose();

        context = getContext(tree, Region.TREE_CELL, ENABLED);
        cellStyle = SeaGlassLookAndFeel.updateStyle(context, this);
        context.dispose();
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void installListeners() {
        super.installListeners();
        tree.addPropertyChangeListener(this);
    }

    /**
     * @inheritDoc
     */
    @Override
    public SeaGlassContext getContext(JComponent c) {
        return getContext(c, SeaGlassLookAndFeel.getComponentState(c));
    }

    private SeaGlassContext getContext(JComponent c, int state) {
        return SeaGlassContext.getContext(SeaGlassContext.class, c, SeaGlassLookAndFeel.getRegion(c), style, state);
    }

    private SeaGlassContext getContext(JComponent c, Region region) {
        return getContext(c, region, getComponentState(c, region));
    }

    private SeaGlassContext getContext(JComponent c, Region region, int state) {
        return SeaGlassContext.getContext(SeaGlassContext.class, c, region, cellStyle, state);
    }

    private int getComponentState(JComponent c, Region region) {
        // Always treat the cell as selected, will be adjusted appropriately
        // when painted.
        return ENABLED | SELECTED;
    }

    /**
     * @inheritDoc
     */
    @Override
    protected TreeCellEditor createDefaultCellEditor() {
        TreeCellRenderer renderer = tree.getCellRenderer();
        DefaultTreeCellEditor editor;

        if (renderer != null && (renderer instanceof DefaultTreeCellRenderer)) {
            editor = new SynthTreeCellEditor(tree, (DefaultTreeCellRenderer) renderer);
        } else {
            editor = new SynthTreeCellEditor(tree, null);
        }
        return editor;
    }

    /**
     * @inheritDoc
     */
    @Override
    protected TreeCellRenderer createDefaultCellRenderer() {
        return new SynthTreeCellRenderer();
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void uninstallDefaults() {
        SeaGlassContext context = getContext(tree, ENABLED);

        style.uninstallDefaults(context);
        context.dispose();
        style = null;

        context = getContext(tree, Region.TREE_CELL, ENABLED);
        cellStyle.uninstallDefaults(context);
        context.dispose();
        cellStyle = null;

        if (tree.getTransferHandler() instanceof UIResource) {
            tree.setTransferHandler(null);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void uninstallListeners() {
        super.uninstallListeners();
        tree.removePropertyChangeListener(this);
    }

    /**
     * Notifies this UI delegate to repaint the specified component. This method
     * paints the component background, then calls the
     * {@link #paint(SynthContext,Graphics)} method.
     *
     * <p>
     * In general, this method does not need to be overridden by subclasses. All
     * Look and Feel rendering code should reside in the {@code paint} method.
     *
     * @param g
     *            the {@code Graphics} object used for painting
     * @param c
     *            the component being painted
     * @see #paint(SynthContext,Graphics)
     */
    @Override
    public void update(Graphics g, JComponent c) {
        SeaGlassContext context = getContext(c);

        SeaGlassLookAndFeel.update(context, g);
        context.getPainter().paintTreeBackground(context, g, 0, 0, c.getWidth(), c.getHeight());
        paint(context, g);
        context.dispose();
    }

    /**
     * @inheritDoc
     */
    @Override
    public void paintBorder(SynthContext context, Graphics g, int x, int y, int w, int h) {
        ((SeaGlassContext)context).getPainter().paintTreeBorder(context, g, x, y, w, h);
    }

    /**
     * Paints the specified component according to the Look and Feel.
     * <p>
     * This method is not used by Synth Look and Feel. Painting is handled by
     * the {@link #paint(SynthContext,Graphics)} method.
     *
     * @param g
     *            the {@code Graphics} object used for painting
     * @param c
     *            the component being painted
     * @see #paint(SynthContext,Graphics)
     */
    @Override
    public void paint(Graphics g, JComponent c) {
        SeaGlassContext context = getContext(c);

        paint(context, g);
        context.dispose();
    }

    /**
     * Paints the specified component.
     *
     * @param context
     *            context for the component being painted
     * @param g
     *            the {@code Graphics} object used for painting
     * @see #update(Graphics,JComponent)
     */
    protected void paint(SynthContext context, Graphics g) {
        paintContext = (SeaGlassContext)context;

        updateLeadSelectionRow();

        Rectangle paintBounds = g.getClipBounds();
        Insets insets = tree.getInsets();
        TreePath initialPath = getClosestPathForLocation(tree, 0, paintBounds.y);
        Enumeration paintingEnumerator = treeState.getVisiblePathsFrom(initialPath);
        int row = treeState.getRowForPath(initialPath);
        int endY = paintBounds.y + paintBounds.height;
        TreeModel treeModel = tree.getModel();
        SeaGlassContext cellContext = getContext(tree, Region.TREE_CELL);

        drawingCache.clear();

        setHashColor(context.getStyle().getColor(context, ColorType.FOREGROUND));

        if (paintingEnumerator != null) {
            // First pass, draw the rows

            boolean done = false;
            boolean isExpanded;
            boolean hasBeenExpanded;
            boolean isLeaf;
            Rectangle rowBounds = new Rectangle(0, 0, tree.getWidth(), 0);
            Rectangle bounds;
            TreePath path;
            TreeCellRenderer renderer = tree.getCellRenderer();
            DefaultTreeCellRenderer dtcr = (renderer instanceof DefaultTreeCellRenderer) ? (DefaultTreeCellRenderer) renderer : null;

            configureRenderer(cellContext);
            while (!done && paintingEnumerator.hasMoreElements()) {
                path = (TreePath) paintingEnumerator.nextElement();
                if (path != null) {
                    isLeaf = treeModel.isLeaf(path.getLastPathComponent());
                    if (isLeaf) {
                        isExpanded = hasBeenExpanded = false;
                    } else {
                        isExpanded = treeState.getExpandedState(path);
                        hasBeenExpanded = tree.hasBeenExpanded(path);
                    }
                    bounds = getPathBounds(tree, path);
                    rowBounds.y = bounds.y;
                    rowBounds.height = bounds.height;
                    paintRow(renderer, dtcr, paintContext, cellContext, g, paintBounds, insets, bounds, rowBounds, path, row, isExpanded,
                        hasBeenExpanded, isLeaf);
                    if ((bounds.y + bounds.height) >= endY) {
                        done = true;
                    }
                } else {
                    done = true;
                }
                row++;
            }

            // Draw the connecting lines and controls.
            // Find each parent and have them draw a line to their last child
            boolean rootVisible = tree.isRootVisible();
            TreePath parentPath = initialPath;
            parentPath = parentPath.getParentPath();
            while (parentPath != null) {
                paintVerticalPartOfLeg(g, paintBounds, insets, parentPath);
                drawingCache.put(parentPath, Boolean.TRUE);
                parentPath = parentPath.getParentPath();
            }
            done = false;
            paintingEnumerator = treeState.getVisiblePathsFrom(initialPath);
            while (!done && paintingEnumerator.hasMoreElements()) {
                path = (TreePath) paintingEnumerator.nextElement();
                if (path != null) {
                    isLeaf = treeModel.isLeaf(path.getLastPathComponent());
                    if (isLeaf) {
                        isExpanded = hasBeenExpanded = false;
                    } else {
                        isExpanded = treeState.getExpandedState(path);
                        hasBeenExpanded = tree.hasBeenExpanded(path);
                    }
                    bounds = getPathBounds(tree, path);
                    // See if the vertical line to the parent has been drawn.
                    parentPath = path.getParentPath();
                    if (parentPath != null) {
                        if (drawingCache.get(parentPath) == null) {
                            paintVerticalPartOfLeg(g, paintBounds, insets, parentPath);
                            drawingCache.put(parentPath, Boolean.TRUE);
                        }
                        paintHorizontalPartOfLeg(g, paintBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
                    } else if (rootVisible && row == 0) {
                        paintHorizontalPartOfLeg(g, paintBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
                    }
                    if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf)) {
                        paintExpandControl(g, paintBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
                    }
                    if ((bounds.y + bounds.height) >= endY) {
                        done = true;
                    }
                } else {
                    done = true;
                }
                row++;
            }
        }
        cellContext.dispose();

        paintDropLine(g);

        // Empty out the renderer pane, allowing renderers to be gc'ed.
        rendererPane.removeAll();

        paintContext = null;
    }

    private void configureRenderer(SeaGlassContext context) {
        TreeCellRenderer renderer = tree.getCellRenderer();

        if (renderer instanceof DefaultTreeCellRenderer) {
            DefaultTreeCellRenderer r = (DefaultTreeCellRenderer) renderer;
            SeaGlassStyle style = (SeaGlassStyle)context.getStyle();

            context.setComponentState(ENABLED | SELECTED);
            Color color = r.getTextSelectionColor();
            if (color == null || (color instanceof UIResource)) {
                r.setTextSelectionColor(style.getColor(context, ColorType.TEXT_FOREGROUND));
            }
            color = r.getBackgroundSelectionColor();
            if (color == null || (color instanceof UIResource)) {
                r.setBackgroundSelectionColor(style.getColor(context, ColorType.TEXT_BACKGROUND));
            }

            context.setComponentState(ENABLED);
            color = r.getTextNonSelectionColor();
            if (color == null || color instanceof UIResource) {
                r.setTextNonSelectionColor(style.getColorForState(context, ColorType.TEXT_FOREGROUND));
            }
            color = r.getBackgroundNonSelectionColor();
            if (color == null || color instanceof UIResource) {
                r.setBackgroundNonSelectionColor(style.getColorForState(context, ColorType.TEXT_BACKGROUND));
            }
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, TreePath path, int row,
        boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) {
        if (drawHorizontalLines) {
            super.paintHorizontalPartOfLeg(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left, int right) {
        paintContext.getStyle().getGraphicsUtils(paintContext)
            .drawLine(paintContext, "Tree.horizontalLine", g, left, y, right, y, linesStyle);
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds, Insets insets, TreePath path) {
        if (drawVerticalLines) {
            super.paintVerticalPartOfLeg(g, clipBounds, insets, path);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void paintVerticalLine(Graphics g, JComponent c, int x, int top, int bottom) {
        paintContext.getStyle().getGraphicsUtils(paintContext)
            .drawLine(paintContext, "Tree.verticalLine", g, x, top, x, bottom, linesStyle);
    }

    private void paintRow(TreeCellRenderer renderer, DefaultTreeCellRenderer dtcr, SeaGlassContext treeContext, SeaGlassContext cellContext,
        Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, Rectangle rowBounds, TreePath path, int row, boolean isExpanded,
        boolean hasBeenExpanded, boolean isLeaf) {
        // Don't paint the renderer if editing this row.
        boolean selected = tree.isRowSelected(row);

        JTree.DropLocation dropLocation = tree.getDropLocation();
        boolean isDrop = dropLocation != null && dropLocation.getChildIndex() == -1 && path == dropLocation.getPath();

        int state = ENABLED;
        if (selected || isDrop) {
            state |= SELECTED;
        }

        if (tree.isFocusOwner() && row == getLeadSelectionRow()) {
            state |= FOCUSED;
        }

        cellContext.setComponentState(state);

        if (dtcr != null && (dtcr.getBorderSelectionColor() instanceof UIResource)) {
            dtcr.setBorderSelectionColor(style.getColor(cellContext, ColorType.FOCUS));
        }
        SeaGlassLookAndFeel.updateSubregion(cellContext, g, rowBounds);
        cellContext.getPainter().paintTreeCellBackground(cellContext, g, rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height);
        cellContext.getPainter().paintTreeCellBorder(cellContext, g, rowBounds.x, rowBounds.y, rowBounds.width, rowBounds.height);
        if (editingComponent != null && editingRow == row) {
            return;
        }

        int leadIndex;

        if (tree.hasFocus()) {
            leadIndex = getLeadSelectionRow();
        } else {
            leadIndex = -1;
        }

        Component component = renderer.getTreeCellRendererComponent(tree, path.getLastPathComponent(), selected, isExpanded, isLeaf, row,
            (leadIndex == row));

        rendererPane.paintComponent(g, component, tree, bounds.x, bounds.y, bounds.width, bounds.height, true);
    }

    private int findCenteredX(int x, int iconWidth) {
        return tree.getComponentOrientation().isLeftToRight() ? x - (int) Math.ceil(iconWidth / 2.0) : x
                - (int) Math.floor(iconWidth / 2.0);
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void paintExpandControl(Graphics g, Rectangle clipBounds, Insets insets, Rectangle bounds, TreePath path, int row,
        boolean isExpanded, boolean hasBeenExpanded, boolean isLeaf) {
        // modify the paintContext's state to match the state for the row
        // this is a hack in that it requires knowledge of the subsequent
        // method calls. The point is, the context used in drawCentered
        // should reflect the state of the row, not of the tree.
        boolean isSelected = tree.getSelectionModel().isPathSelected(path);
        int state = paintContext.getComponentState();
        if (isSelected) {
            paintContext.setComponentState(state | SynthConstants.SELECTED);
        }
        super.paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
        paintContext.setComponentState(state);
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void drawCentered(Component c, Graphics graphics, Icon icon, int x, int y) {
        int w = SynthIcon.getIconWidth(icon, paintContext);
        int h = SynthIcon.getIconHeight(icon, paintContext);

        SynthIcon.paintIcon(icon, paintContext, graphics, findCenteredX(x, w), y - h / 2, w, h);
    }

    /**
     * @inheritDoc
     */
    @Override
    public void propertyChange(PropertyChangeEvent event) {
        if (SeaGlassLookAndFeel.shouldUpdateStyle(event)) {
            updateStyle((JTree) event.getSource());
        }

        if ("dropLocation" == event.getPropertyName()) {
            JTree.DropLocation oldValue = (JTree.DropLocation) event.getOldValue();
            repaintDropLocation(oldValue);
            repaintDropLocation(tree.getDropLocation());
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    protected void paintDropLine(Graphics g) {
        JTree.DropLocation loc = tree.getDropLocation();
        if (!isDropLine(loc)) {
            return;
        }

        Color c = (Color) style.get(paintContext, "Tree.dropLineColor");
        if (c != null) {
            g.setColor(c);
            Rectangle rect = getDropLineRect(loc);
            g.fillRect(rect.x, rect.y, rect.width, rect.height);
        }
    }

    private void repaintDropLocation(JTree.DropLocation loc) {
        if (loc == null) {
            return;
        }

        Rectangle r;

        if (isDropLine(loc)) {
            r = getDropLineRect(loc);
        } else {
            r = tree.getPathBounds(loc.getPath());
            if (r != null) {
                r.x = 0;
                r.width = tree.getWidth();
            }
        }

        if (r != null) {
            tree.repaint(r);
        }
    }

    /**
     * @inheritDoc
     */
    @Override
    protected int getRowX(int row, int depth) {
        return super.getRowX(row, depth) + padding;
    }

    private class SynthTreeCellRenderer extends DefaultTreeCellRenderer implements UIResource {
        SynthTreeCellRenderer() {
        }

        @Override
        public String getName() {
            return "Tree.cellRenderer";
        }

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row,
            boolean hasFocus) {
            if (!useTreeColors && (sel || hasFocus)) {
                SeaGlassLookAndFeel.setSelectedUI((SynthLabelUI) SeaGlassLookAndFeel.getUIOfType(getUI(), SynthLabelUI.class), sel, hasFocus,
                    tree.isEnabled(), false);
            } else {
                SeaGlassLookAndFeel.resetSelectedUI();
            }
            return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
        }

        @Override
        public void paint(Graphics g) {
            paintComponent(g);
            if (hasFocus) {
                SeaGlassContext context = getContext(tree, Region.TREE_CELL);

                if (context.getStyle() == null) {
                    assert false : "SynthTreeCellRenderer is being used " + "outside of UI that created it";
                    return;
                }
                int imageOffset = 0;
                Icon currentI = getIcon();

                if (currentI != null && getText() != null) {
                    imageOffset = currentI.getIconWidth() + Math.max(0, getIconTextGap() - 1);
                }
                if (selected) {
                    context.setComponentState(ENABLED | SELECTED);
                } else {
                    context.setComponentState(ENABLED);
                }
                if (getComponentOrientation().isLeftToRight()) {
                    context.getPainter().paintTreeCellFocus(context, g, imageOffset, 0, getWidth() - imageOffset, getHeight());
                } else {
                    context.getPainter().paintTreeCellFocus(context, g, 0, 0, getWidth() - imageOffset, getHeight());
                }
                context.dispose();
            }
            SeaGlassLookAndFeel.resetSelectedUI();
        }
    }

    private static class SynthTreeCellEditor extends DefaultTreeCellEditor {
        public SynthTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
            super(tree, renderer);
            setBorderSelectionColor(null);
        }

        @Override
        protected TreeCellEditor createTreeCellEditor() {
            JTextField tf = new JTextField() {
                @Override
                public String getName() {
                    return "Tree.cellEditor";
                }
            };
            DefaultCellEditor editor = new DefaultCellEditor(tf);

            // One click to edit.
            editor.setClickCountToStart(1);
            return editor;
        }
    }

    //
    // BasicTreeUI directly uses expandIcon outside of the Synth methods.
    // To get the correct context we return an instance of this that fetches
    // the SynthContext as needed.
    //
    private class ExpandedIconWrapper extends SeaGlassIcon {
        public ExpandedIconWrapper() {
            super("Tree", "expandedIconPainter", 7, 7);
        }

        public void paintIcon(SynthContext context, Graphics g, int x, int y, int w, int h) {
            if (context == null) {
                context = getContext(tree);
                SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h);
                ((SeaGlassContext)context).dispose();
            } else {
                SynthIcon.paintIcon(expandedIcon, context, g, x, y, w, h);
            }
        }

        public int getIconWidth(SynthContext context) {
            int width;
            if (context == null) {
                context = getContext(tree);
                width = SynthIcon.getIconWidth(expandedIcon, context);
                ((SeaGlassContext)context).dispose();
            } else {
                width = SynthIcon.getIconWidth(expandedIcon, context);
            }
            return width;
        }

        public int getIconHeight(SynthContext context) {
            int height;
            if (context == null) {
                context = getContext(tree);
                height = SynthIcon.getIconHeight(expandedIcon, context);
                ((SeaGlassContext)context).dispose();
            } else {
                height = SynthIcon.getIconHeight(expandedIcon, context);
            }
            return height;
        }
    }
}
